home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Graphics Plus
/
Graphics Plus.iso
/
sgi
/
editors
/
kali.lha
/
kali
/
symmetry.c
< prev
next >
Wrap
C/C++ Source or Header
|
1992-09-14
|
14KB
|
604 lines
/* */
/*** symmetry.c - Nina Amenta, Aug. 1989 ****/
/* */
#include <math.h>
#include <stdio.h>
#include <gl.h>
#include "symmetry.h"
LINE *AddLineToObject();
LINE *AllRotations();
LINE *MakeCurrentObject();
LINE *ReadPattern();
LINE *ReadLine();
POINT ORIGIN = {0.0,0.0};
LINE *NewLine();
void PickLine();
float distance();
/* symmetry =
admissible transformations
translation vector1 (screen basis)
translation vector2 (screen basis)
#reflections
reflection vectors (standard basis)
glide reflection flag
#rotations
note: the SCREEN basis is the lattice as displayed, ie under user control.
Internally, things assume the STANDARD {1,0},{0,1} basis for the lattice.
*/
SYMMETRY SYMTAB[NUM_SYM] = {
{0,{60.0,-103.923},{60.0,103.923},0,
{{0.0,0.0},{0.0,0.0}},0,3,"p3 - 3-way rotation"},
{ANG | RAT,{100.0,0.0},{0.0,100.0},0,
{{0.0,0.0},{0.0,0.0}},0,2,"p2 - 2 way rotation"},
{ANG | RAT,{100.0,-100.0},{100.0,100.0},0,
{{0.0,0.0},{0.0,0.0}},0,0,"p1 - translation"},
{RAT,{100.0,0.0},{0.0,100.0},1,
{{0.0,0.5},{0.0,0.0}},GLIDE,0,"pg - 1 glide reflection"},
{RAT,{125.0,0.0},{0.0,125.0},2,
{{0.5,0.0},{0.0,0.5}},GLIDE,0,"pgg - 2 glide reflections"},
{RAT,{125.0,0.0},{0.0,125.0},1,
{{0.0,0.5},{0.0,0.0}},GLIDE,2,"pmg - glide reflection w/ 2-way rotation"},
{RAT,{125.0,0.0},{0.0,125.0},1,
{{0.0,0.5},{0.0,0.0}},0,0,"pm - 1 lattice reflection"},
{ANG,{60.0,-103.923},{60.0,103.923},1,
{{0.5,0.5},{0.0,0.0}},0,0,"cm - 1 off-lattice reflection"},
{RAT,{125.0,0.0},{0.0,125.0},1,
{{0.0,0.5},{0.0,0.0}},0,2,"pmm - 2 lattice reflections"},
{ANG,{100.0,-100.0},{100.0,100.0},1,
{{0.5,0.5},{0.0,0.0}},0,2,"cmm - 2 off-lattice reflections"},
{0,{90.0,-155.884},{90.0,155.884},1,
{{0.0,0.5},{0.0,0.0}},0,3,"p31m - 3 lattice reflections"},
{0,{90.0,-155.884},{90.0,155.884},1,
{{1.0,2.0},{0.0,0.0}},0,3,"p3m1 - 3 off-lattice reflections"},
{0,{100.0,-100.0},{100.0,100.0},0,
{{0.0,0.0},{0.0,0.0}},0,4,"p4 - 4-way rotation"},
{0,{100.0,-100.0},{100.0,100.0},1,
{{0.5,0.5},{0.0,0.0}},GLIDE,4,"p4g - glide reflection w/ 4-way rotation"},
{0,{100.0,-100.0},{100.0,100.0},1,
{{0.5,0.5},{0.0,0.0}},0,4,"p4m - reflection w/ 4-way rotation"},
{0,{90.0,-155.884},{90.0,155.884},0,
{{0.0,0.0},{0.0,0.0}},0,6,"p6 - 6-way rotation"},
{0,{90.0,-155.884},{90.0,155.884},1,
{{0.0,0.5},{0.0,0.0}},0,6,"p6m - reflection w/ 6-way rotation"}
};
DefineSymWindow(s_rect,sym,w_rect,scale)
RECTANGLE *w_rect,*s_rect;
SYMMETRY *sym;
float scale;
{
float x,y;
VECTOR vec1,vec2;
extern WINDOW win;
RearrangeVectors(&(sym->v1),&(sym->v2),&vec1,&vec2);
x = vec1.x + vec2.x;
y = vec2.y - vec1.y;
s_rect->width = ((int)(scale*w_rect->width/x) + 1) * x;
s_rect->height = ((int)(scale*w_rect->height/y) + 1) * y;
winset(win);
ortho2(0.0,scale*w_rect->width,0.0,scale*w_rect->height);
}
int SetUpSymmetry(s,pointpointer,xforms,s_rec)
SYMMETRY *s;
POINT **pointpointer;
XFORM xforms[];
RECTANGLE *s_rec;
{
int i=0; int j;
VECTOR vec1,vec2;
RECTANGLE virtual;
POINT *pts;
int maxpts;
virtual.x = virtual.y = 0;
virtual.width = s_rec->width;
virtual.height = s_rec->height;
if (*pointpointer != NULL) free(*pointpointer);
RearrangeVectors(&(s->v1),&(s->v2),&vec1,&vec2);
maxpts = 2 * (s_rec->width/(vec1.x+vec2.x) + 1) *
(s_rec->height/(vec2.y-vec1.y) + 1); /* plus 1 for good luck */
pts = (POINT *)malloc(maxpts*sizeof(POINT));
*pointpointer = pts;
pts[0].x = 0.0; pts[0].y = 0.0;
/* lay down points of symmetry */
for (;;)
{
j = i; /* begining of this last row */
while (RectIncludesPoint(virtual,pts[i]))
{
bump(pts+i,pts+i+1,1,&vec1);
i++;
}
bump(pts+j,pts+i,1,&vec2);
if (PointRightOfRect(pts[i],virtual)) break;
while (RectIncludesPoint(virtual,pts[i]))
bump(pts+i,pts+i,-1,&vec1);
while (!RectIncludesPoint(virtual,pts[i])) {
bump(pts+i,pts+i,1,&vec1);
if (PointRightOfRect(pts[i],virtual)) break;
}
}
SetUpParameterization(&(s->v1),&(s->v2),xforms[3],xforms[4]);
if (s->rot>1)
SetUpRot(2.0*M_PI/(s->rot),xforms[0]);
if (s->refl!=0)
for (j=0; j<s->refl; j++)
SetUpRefl(&(s->reflections[j]),xforms[j+1],xforms[3]);
return(i);
}
RearrangeVectors(in1,in2,vec1,vec2)
VECTOR *in1,*in2,*vec1,*vec2;
{
VECTOR tmp;
CopyVector(in1,vec1);
CopyVector(in2,vec2);
if (vec2->x < 0.0) VectorScalarMult(vec2,-1.0);
if (vec1->x < 0.0) VectorScalarMult(vec1,-1.0);
if ((vec1->y > 0.0) && (vec2->y < 0.0)) {
CopyVector(vec1,&tmp); CopyVector(vec2,vec1); CopyVector(&tmp,vec2);
}
while ((vec1->y > 0.0) || (vec2->y < 0.0)) {
vec2->x = vec1->x - vec2->x;
vec2->y = vec1->y - vec2->y;
if (vec2->x < 0.0) VectorScalarMult(vec2,-1.0);
if ((vec1->y > 0.0) && (vec2->y < 0.0)) {
CopyVector(vec1,&tmp); CopyVector(vec2,vec1); CopyVector(&tmp,vec2);
}
}
}
SetUpParameterization(vec1,vec2,std2scr,scr2std)
VECTOR *vec1,*vec2;
XFORM std2scr,scr2std;
{
std2scr[0] = vec1->x;
std2scr[1] = vec1->y;
std2scr[2] = vec2->x;
std2scr[3] = vec2->y;
InvertMatrix(std2scr,scr2std);
}
SetUpRefl(v,xform,std2scr)
VECTOR *v;
XFORM xform,std2scr;
{
XFORM temp;
double angle;
VECTOR w;
/* reflection vector is in standard basis, convert to screen basis */
VectorMatrixMult(v,std2scr,&w);
angle=atan2((double)w.y,(double)w.x);
/* reflection across the x axis */
temp[0] = 1;
temp[1] = temp[2] = 0;
temp[3] = -1;
/* rotate to x axis */
SetUpRot(-angle,xform);
/* reflect */
MatrixMultiply(xform,temp,temp);
/* rotate back */
SetUpRot(angle,xform);
MatrixMultiply(temp,xform,xform);
}
SetUpRot(angle,xform)
double angle;
float *xform;
{
xform[1] = sin(angle);
xform[2] = -sin(angle);
xform[0] = xform[3] = cos(angle);
}
DrawPoints(pts,cnt)
POINT *pts;
int cnt;
{
int i;
for (i=0; i<cnt; i++)
DrawDot(&pts[i]);
}
LINE *MakeCurrentObject(Lines,sym,xforms,bounds)
LINE *Lines;
SYMMETRY *sym;
XFORM xforms[];
RECTANGLE *bounds;
{
int i,j,pos_count;
LINE cur,temp,*line_ptr,*obj;
VECTOR glide[2];
obj = NULL;
bounds->x = bounds->y = bounds->width = bounds->height = 0.0;
/* transform glide reflection vectors from standard to current basis */
if (sym->glide == GLIDE) {
VectorMatrixMult(&(sym->reflections[0]),xforms[3],&(glide[0]));
VectorMatrixMult(&(sym->reflections[1]),xforms[3],&(glide[1]));
}
else {
glide[0].x = glide[1].x = glide[0].y = glide[0].y = 0.0;
}
for (line_ptr=Lines; line_ptr != NULL; line_ptr = line_ptr->next)
{
CopyLine(line_ptr,&cur);
/* Convert from standard basis to screen coordinate basis */
MatrixMultiply(cur.m,xforms[3],cur.m);
pos_count = 0; /* used in picking */
obj = AllRotations(&cur,xforms[0],sym,obj,bounds,&pos_count);
if (sym->refl > 0)
{
for (i=1; i<=sym->refl; i++)
{
temp.id = cur.id;
MatrixMultiply(cur.m,xforms[i],temp.m);
TranslateLine(&temp,&(glide[i-1]),1,&temp);
obj = AllRotations(&temp,xforms[0],sym,obj,bounds,&pos_count);
if (i==2)
{
MatrixMultiply(temp.m,xforms[1],temp.m);
TranslateLine(&temp,&(glide[0]),1,&temp);
obj = AllRotations(&temp,xforms[0],sym,obj,bounds,&pos_count);
}
}
}
}
return(obj);
}
FreeObject(obj)
LINE *obj;
{
LINE *cur;
while (obj != NULL)
{
cur = obj;
obj = obj->next;
free(cur);
}
}
LINE *AllRotations(l,xform,sym,obj,bounds,pos_count)
LINE *l,*obj;
MATRIX xform;
SYMMETRY *sym;
RECTANGLE *bounds;
int *pos_count;
{
int j;
LINE temp;
CopyLine(l,&temp);
obj = AddLineToObject(obj,&temp,bounds,pos_count);
for (j=1; j<sym->rot; j++)
{
MatrixMultiply(temp.m,xform,temp.m);
obj = AddLineToObject(obj,&temp,bounds,pos_count);
}
return(obj);
}
LINE *AddLineToObject(obj,l,r,pos_count)
LINE *obj,*l;
RECTANGLE *r;
int *pos_count;
{
LINE *new;
new = NewLine(obj);
new->obj_pos = (*pos_count)++;
CopyLine(l,new);
AdjustBoundingBox(new,r);
return(new);
}
AdjustBoundingBox(l,r)
LINE *l;
RECTANGLE *r;
{
float min,max;
GetMinMax(r->x,r->width,l->m[EX],l->m[SX],&min,&max);
r->x = min;
r->width = max;
GetMinMax(r->y,r->height,l->m[EY],l->m[SY],&min,&max);
r->y = min;
r->height = max;
}
GetMinMax(a,b,c,d,min,max)
float a,b,c,d,*min,*max;
{
float tmp;
if (b < a) { tmp=a; a=b; b=tmp;}
if (c < a) { tmp=a; a=c; c=tmp;}
if (d < a) { tmp=a; a=d; d=tmp;}
if (b > d) { tmp=b; b=d; d=tmp;}
if (c > d) { tmp=c; c=d; d=tmp;}
*min = a;
*max = d;
}
/* Translate the design to each of the centers of symmetry on the screen,
and draw it. Call ReplicateOffEdges to draw the pieces of designs around
the edges of the picture that belong to centers of symmetry that are just
off the screen. */
ReplicateObject(rect,obj,pts,count,bounds,vec1,vec2,drawing_routine)
RECTANGLE *rect;
LINE *obj;
POINT *pts;
int count;
RECTANGLE *bounds;
VECTOR *vec1,*vec2;
void (*drawing_routine) ();
{
int i;
for (i=0; i<count; i++)
{
/* For picking */
if (drawing_routine == PickLine)
LogTranslation(i);
TranslateCoordinates(pts[i].x,pts[i].y,0.0);
DrawObject(obj,drawing_routine);
ReplicateOffEdges
(rect,obj,&pts[i],bounds,vec1,vec2,drawing_routine);
TranslateBack();
}
}
/* Rearranges the line so the closest endpoint to the point
is EX,EY */
ClosestEndpoint(line,p)
LINE *line;
POINT * p;
{
float temp;
temp = distance(line->m[EX],line->m[EY],p->x,p->y);
temp = distance(line->m[SX],line->m[SY],p->x,p->y);
if (distance(line->m[EX],line->m[EY],p->x,p->y) >
distance(line->m[SX],line->m[SY],p->x,p->y))
{
temp = line->m[SX]; line->m[SX] = line->m[EX]; line->m[EX] = temp;
temp = line->m[SY]; line->m[SY] = line->m[EY]; line->m[EY] = temp;
}
}
float distance(qx,qy,px,py)
float qx,qy,px,py;
{
float temp;
temp = sqrt((qx-px)*(qx-px) + (qy-py)*(qy-py));
return(temp);
}
/* Look at all adjacent possible centers of symmetry in the lattice.
If any of these are off the screen, but the current bounding box of
the design intersects the screen, draw the design at that center.
Then try another step in the same direction. */
ReplicateOffEdges(screen,obj,p,bounds,vec1,vec2,drawing_routine)
RECTANGLE *screen;
LINE *obj;
POINT *p;
RECTANGLE *bounds;
VECTOR *vec1,*vec2;
void (*drawing_routine) ();
{
VECTOR v;
DrawIfNecessary(screen,obj,p,bounds,vec1,1,vec1,vec2,drawing_routine);
DrawIfNecessary(screen,obj,p,bounds,vec2,1,vec1,vec2,drawing_routine);
DrawIfNecessary(screen,obj,p,bounds,vec1,-1,vec1,vec2,drawing_routine);
DrawIfNecessary(screen,obj,p,bounds,vec2,-1,vec1,vec2,drawing_routine);
AddVector(vec1,vec2,1,&v);
DrawIfNecessary(screen,obj,p,bounds,&v,1,vec1,vec2,drawing_routine);
DrawIfNecessary(screen,obj,p,bounds,&v,-1,vec1,vec2,drawing_routine);
AddVector(vec1,vec2,-1,&v);
DrawIfNecessary(screen,obj,p,bounds,&v,1,vec1,vec2,drawing_routine);
DrawIfNecessary(screen,obj,p,bounds,&v,-1,vec1,vec2,drawing_routine);
}
DrawIfNecessary(screen,obj,p,bounds,vec,direction,vec1,vec2,drawing_routine)
RECTANGLE *screen;
LINE *obj;
POINT *p;
RECTANGLE *bounds;
VECTOR *vec,*vec1,*vec2;
int direction;
void (*drawing_routine) ();
{
POINT q;
bump(p,&q,direction,vec);
if (!RectIncludesPoint(*screen,q) &&
BBoxIntersectsRect(&q,bounds,screen))
{
TranslateCoordinates(direction*vec->x,direction*vec->y,0.0);
DrawObject(obj,drawing_routine);
DrawIfNecessary(screen,obj,&q,bounds,vec,direction,
vec1,vec2,drawing_routine);
TranslateBack();
}
}
int BBoxIntersectsRect(p,bounds,screen)
POINT *p;
RECTANGLE *bounds;
RECTANGLE *screen;
{
if (((p->x+bounds->width > screen->x) &&
(p->x+bounds->x < screen->x+screen->width)) &&
((p->y+bounds->height > screen->y) &&
(p->y+bounds->y < screen->y+screen->height))) return(TRUE);
return(FALSE);
}
TranslateLine(s,v,scale,d)
LINE *s,*d;
VECTOR *v;
int scale;
{
MATRIX temp;
temp[0] = s->m[0]+scale*v->x;
temp[1] = s->m[1]+scale*v->y;
temp[2] = s->m[2]+scale*v->x;
temp[3] = s->m[3]+scale*v->y;
CopyMatrix(temp,d->m);
d->id = s->id;
}
CopyMatrix(f,t)
MATRIX f,t;
{
int i;
for (i=0;i<4;i++) t[i]=f[i];
}
CopyLine(f,t)
LINE *f,*t;
{
CopyMatrix(f->m,t->m);
t->id = f->id;
}
CopyVector(v,w)
VECTOR *v,*w;
{
w->x = v->x; w->y = v->y;
}
CopyRectangle(f,t)
RECTANGLE *f,*t;
{
t->x = f->x; t->y = f->y;
t->width = f->width; t->height = f->height;
}
AddVector(v,w,scale,d)
VECTOR *v,*w,*d;
int scale;
{
d->x = v->x + scale*w->x;
d->y = v->y + scale*w->y;
}
MatrixMultiply(s,t,d)
MATRIX s,t,d;
{
MATRIX temp;
int i;
temp[0] = s[0]*t[0]+s[1]*t[2];
temp[1] = s[0]*t[1]+s[1]*t[3];
temp[2] = s[2]*t[0]+s[3]*t[2];
temp[3] = s[2]*t[1]+s[3]*t[3];
CopyMatrix(temp,d);
}
VectorMatrixMult(s,m,d)
VECTOR *s,*d;
MATRIX m;
{
VECTOR temp;
temp.x = s->x*m[0]+s->y*m[2];
temp.y = s->x*m[1]+s->y*m[3];
d->x = temp.x; d->y = temp.y;
}
VectorScalarMult(v,f)
VECTOR *v;
float f;
{
v->x *= f; v->y *= f;
}
InvertMatrix(s,d)
MATRIX s,d;
{
float det;
det = s[0]*s[3] - s[1]*s[2];
d[0] = s[3]/det;
d[1] = -s[1]/det;
d[2] = -s[2]/det;
d[3] = s[0]/det;
}
NewId(line)
LINE *line;
{
static short newid=0;
line->id = newid++;
}
LINE *NewLine(Lines)
LINE *Lines;
{
LINE *new;
new = (LINE*) malloc(sizeof(LINE));
new->next = Lines;
return(new);
}
LINE *ReadPattern(Lines,pat)
LINE *Lines;
FILE *pat;
{
LINE *cur;
int id=0;
for (cur=ReadLine(pat); cur!=NULL; cur=ReadLine(pat))
{
cur->next = Lines;
cur->id = id++;
Lines = cur;
}
return(Lines);
}
LINE *ReadLine(pat)
FILE *pat;
{
LINE *l;
l = NewLine(NULL);
if (fscanf(pat,"%f %f %f %f",&l->m[0],&l->m[1],&l->m[2],&l->m[3])!=EOF)
return (l);
else
{
free(l);
return(NULL);
}
}